package com.example.studentregistration.service.impl;

import cn.hutool.core.io.IoUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.example.studentregistration.mapper.CheckInMapper;
import com.example.studentregistration.mapper.DormBuildingMapper;
import com.example.studentregistration.mapper.DormRoomMapper;
import com.example.studentregistration.mapper.StudentMapper;
import com.example.studentregistration.pojo.CheckIn;
import com.example.studentregistration.pojo.DormBuilding;
import com.example.studentregistration.pojo.DormRoom;
import com.example.studentregistration.service.CheckInService;
import com.example.studentregistration.util.Result;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.Date;
import java.util.List;

@Service
public class CheckInServiceImpl implements CheckInService {

    @Autowired
    private CheckInMapper checkInMapper;
    @Autowired
    private DormRoomMapper dormRoomMapper;
    @Autowired
    private DormBuildingMapper dormBuildingMapper;
    @Autowired
    private StudentMapper studentMapper;

    @Override
    public Result<?> insert(CheckIn entity) {
        int res = checkInMapper.insert(entity);
        return res > 0 ? Result.success("添加成功") : Result.fail("添加失败");
    }

    @Override
    public Result<?> update(CheckIn entity) {
        int res = checkInMapper.update(entity);
        return res > 0 ? Result.success("修改成功") : Result.fail("修改失败");
    }

    @Override
    public Result<?> delete(Integer id) {
        int res = checkInMapper.delete(id);
        return res > 0 ? Result.success("删除成功") : Result.fail("删除失败");
    }

    @Override
    public int batchDelete(List<Integer> ids) {
        if (ids == null || ids.isEmpty()) return 0;
        return checkInMapper.batchDelete(ids);
    }

    @Override
    public Page queryAll(Integer currentPage, Integer pageSize) {
        Page<CheckIn> page = PageHelper.startPage(currentPage, pageSize);
        checkInMapper.findAll();
        return page;
    }

    @Override
    public Result<CheckIn> queryById(Integer id) {
        CheckIn ci = checkInMapper.findById(id);
        return ci == null ? Result.fail("记录不存在") : Result.success(ci);
    }

    private void refreshRoomStatus(DormRoom room) {
        int occ = room.getOccupiedCount() == null ? 0 : room.getOccupiedCount();
        int beds = room.getBedCount() == null ? 0 : room.getBedCount();
        String status;
        if (occ <= 0) status = "空闲";
        else if (occ >= beds) status = "已满";
        else status = "部分空闲";
        room.setRoomStatus(status);
        dormRoomMapper.update(room);
    }

    @Transactional
    @Override
    public Result<?> checkIn(CheckIn entity) {
        try {
            System.out.println("=== 开始办理入住 ===");
            System.out.println("入住数据: " + entity);
            
            // 基本校验
            System.out.println("1. 开始基本校验");
            // 1.1 学生是否存在
            if (entity.getStudentId() == null || entity.getStudentId() <= 0) {
                return Result.fail("学生ID无效");
            }
            int studentExists = studentMapper.existsById(entity.getStudentId());
            if (studentExists <= 0) {
                return Result.fail("学生不存在，请先在学生管理中添加该学生");
            }
            DormRoom room = dormRoomMapper.findById(entity.getRoomId());
            System.out.println("查询房间结果: " + room);
            if (room == null) return Result.fail("房间不存在");
            
            DormBuilding building = dormBuildingMapper.findById(room.getBuildingId());
            System.out.println("查询楼宇结果: " + building);
            if (building == null) return Result.fail("楼宇不存在");

            // 单一活跃记录校验
            System.out.println("2. 开始活跃记录校验");
            CheckIn active = checkInMapper.findActiveByStudentId(entity.getStudentId());
            System.out.println("学生活跃记录: " + active);
            if (active != null) return Result.fail("该学生已有在住记录");
            
            CheckIn bedActive = checkInMapper.findActiveByBed(building.getId(), room.getId(), entity.getBedNo());
            System.out.println("床位活跃记录: " + bedActive);
            if (bedActive != null) return Result.fail("目标床位已被占用");

            // 设置默认状态
            System.out.println("3. 设置默认状态");
            if (entity.getStatus() == null || entity.getStatus().isEmpty()) {
                entity.setStatus("入住中");
            }
            if (entity.getCheckInDate() == null) {
                entity.setCheckInDate(new java.sql.Date(new Date().getTime()));
            }
            // 设置默认操作员ID（数据库字段为NOT NULL）
            if (entity.getOperatorId() == null) {
                entity.setOperatorId(1); // 设置默认操作员ID为1
            }
            entity.setBuildingId(building.getId());
            System.out.println("处理后的入住数据: " + entity);
            
            // 插入入住记录
            System.out.println("4. 开始插入入住记录");
            int res = checkInMapper.insert(entity);
            System.out.println("插入结果: " + res);
            if (res <= 0) return Result.fail("办理失败");

            // 更新房间与楼宇统计
            System.out.println("5. 开始更新统计信息");
            room.setOccupiedCount((room.getOccupiedCount() == null ? 0 : room.getOccupiedCount()) + 1);
            System.out.println("更新房间占用数: " + room.getOccupiedCount());
            refreshRoomStatus(room);
            
            building.setOccupiedBeds((building.getOccupiedBeds() == null ? 0 : building.getOccupiedBeds()) + 1);
            System.out.println("更新楼宇占用床位数: " + building.getOccupiedBeds());
            dormBuildingMapper.update(building);
            
            System.out.println("=== 入住办理成功 ===");
            return Result.success("办理成功");
        } catch (Exception e) {
            System.err.println("=== 入住办理异常 ===");
            System.err.println("异常信息: " + e.getMessage());
            e.printStackTrace();
            // 标记当前事务回滚，但不向上抛出异常，避免直接返回HTTP 500
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return Result.fail(e.getMessage() != null ? e.getMessage() : "办理失败");
        }
    }

    @Transactional
    @Override
    public Result<?> checkOut(Integer id) {
        CheckIn record = checkInMapper.findById(id);
        if (record == null) return Result.fail("记录不存在");
        if ("已退宿".equals(record.getStatus())) return Result.fail("已是退宿状态");
        DormRoom room = dormRoomMapper.findById(record.getRoomId());
        DormBuilding building = dormBuildingMapper.findById(record.getBuildingId());

        record.setStatus("已退宿");
        record.setCheckOutDate(new java.sql.Date(new Date().getTime()));
        int res = checkInMapper.update(record);
        if (res <= 0) return Result.fail("退宿失败");

        // 更新统计
        if (room != null) {
            room.setOccupiedCount(Math.max(0, (room.getOccupiedCount() == null ? 0 : room.getOccupiedCount()) - 1));
            refreshRoomStatus(room);
        }
        if (building != null) {
            building.setOccupiedBeds(Math.max(0, (building.getOccupiedBeds() == null ? 0 : building.getOccupiedBeds()) - 1));
            dormBuildingMapper.update(building);
        }
        return Result.success("退宿成功");
    }

    @Transactional
    @Override
    public Result<?> transfer(Integer recordId, Integer targetRoomId, String targetBedNo) {
        CheckIn record = checkInMapper.findById(recordId);
        if (record == null || !"入住中".equals(record.getStatus())) return Result.fail("只有在住记录才能调换");
        DormRoom srcRoom = dormRoomMapper.findById(record.getRoomId());
        DormBuilding srcBuilding = dormBuildingMapper.findById(record.getBuildingId());

        DormRoom targetRoom = dormRoomMapper.findById(targetRoomId);
        if (targetRoom == null) return Result.fail("目标房间不存在");
        DormBuilding targetBuilding = dormBuildingMapper.findById(targetRoom.getBuildingId());

        // 目标床位是否空闲
        CheckIn bedActive = checkInMapper.findActiveByBed(targetBuilding.getId(), targetRoom.getId(), targetBedNo);
        if (bedActive != null) return Result.fail("目标床位已被占用");

        // 更新记录到新房间/床位
        record.setBuildingId(targetBuilding.getId());
        record.setRoomId(targetRoom.getId());
        record.setBedNo(targetBedNo);
        int res = checkInMapper.update(record);
        if (res <= 0) return Result.fail("调换失败");

        // 统计：源-1，目标+1
        if (srcRoom != null) {
            srcRoom.setOccupiedCount(Math.max(0, (srcRoom.getOccupiedCount() == null ? 0 : srcRoom.getOccupiedCount()) - 1));
            refreshRoomStatus(srcRoom);
        }
        if (targetRoom != null) {
            targetRoom.setOccupiedCount((targetRoom.getOccupiedCount() == null ? 0 : targetRoom.getOccupiedCount()) + 1);
            refreshRoomStatus(targetRoom);
        }
        if (srcBuilding != null && targetBuilding != null && !srcBuilding.getId().equals(targetBuilding.getId())) {
            srcBuilding.setOccupiedBeds(Math.max(0, (srcBuilding.getOccupiedBeds() == null ? 0 : srcBuilding.getOccupiedBeds()) - 1));
            dormBuildingMapper.update(srcBuilding);
            targetBuilding.setOccupiedBeds((targetBuilding.getOccupiedBeds() == null ? 0 : targetBuilding.getOccupiedBeds()) + 1);
            dormBuildingMapper.update(targetBuilding);
        }
        return Result.success("调换成功");
    }

    @Override
    public void exportExcel(HttpServletResponse response) throws IOException {
        List<CheckIn> list = checkInMapper.findAll();
        ExcelWriter writer = ExcelUtil.getWriter();
        writer.write(list, true);
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
        String fileName = URLEncoder.encode("入住记录", "UTF-8");
        response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx");
        ServletOutputStream os = response.getOutputStream();
        writer.flush(os, true);
        writer.close();
        IoUtil.close(os);
    }
}